home *** CD-ROM | disk | FTP | other *** search
- /* Domain header conversion routines
- * Copyright 1991 Phil Karn, KA9Q
- *
- * Additional support for the Domain Name Server
- * by Johan. K. Reinalda, WG7J,
- * based on previous work by Gerard v.d. Grinten, PA0GRI
- */
- #include "global.h"
- #include "mbuf.h"
- #include "domain.h"
-
- #if !defined(_lint)
- static char rcsid[] OPTIONAL = "$Id: domhdr.c,v 1.14 1997/08/19 01:19:22 root Exp root $";
- #endif
-
- static int dn_expand (char *msg, char *eom, char *compressed, char *full, int fullen);
- static char *getq (struct rr ** rrpp, char *msg, char *cp);
- static char *ntohrr (struct rr ** rrpp, char *msg, char *cp);
-
- #ifdef DSERVER
- static char *dn_compress (char *cp, char *name);
- static char *htonrr (struct rr * rr, char *buffer);
- #endif
-
-
- int
- ntohdomain (dhdr, bpp)
- register struct dhdr *dhdr;
- struct mbuf **bpp;
- {
- int16 tmp, len;
- register int16 i;
- char *msg, *cp;
- struct rr **rrpp;
-
- len = len_p (*bpp);
- msg = mallocw ((unsigned) len);
- (void) pullup (bpp, (unsigned char *) msg, len);
- memset ((char *) dhdr, 0, sizeof (*dhdr));
-
- dhdr->id = get16 (&msg[0]);
- tmp = get16 (&msg[2]);
- if (tmp & 0x8000)
- dhdr->qr = 1;
- dhdr->opcode = (tmp >> 11) & 0xf;
- if (tmp & 0x0400)
- dhdr->aa = 1;
- if (tmp & 0x0200)
- dhdr->tc = 1;
- if (tmp & 0x0100)
- dhdr->rd = 1;
- if (tmp & 0x0080)
- dhdr->ra = 1;
- dhdr->rcode = tmp & 0xf;
- dhdr->qdcount = get16 (&msg[4]);
- dhdr->ancount = get16 (&msg[6]);
- dhdr->nscount = get16 (&msg[8]);
- dhdr->arcount = get16 (&msg[10]);
-
- /* Now parse the variable length sections */
- cp = &msg[12];
-
- /* Question section */
- rrpp = &dhdr->questions;
- for (i = 0; i < dhdr->qdcount; i++) {
- if ((cp = getq (rrpp, msg, cp)) == NULLCHAR) {
- free (msg);
- return -1;
- }
- (*rrpp)->source = RR_QUESTION;
- rrpp = &(*rrpp)->next;
- }
- *rrpp = NULLRR;
-
- /* Answer section */
- rrpp = &dhdr->answers;
- for (i = 0; i < dhdr->ancount; i++) {
- if ((cp = ntohrr (rrpp, msg, cp)) == NULLCHAR) {
- free (msg);
- return -1;
- }
- (*rrpp)->source = RR_ANSWER;
- rrpp = &(*rrpp)->next;
- }
- *rrpp = NULLRR;
-
- /* Name server (authority) section */
- rrpp = &dhdr->authority;
- for (i = 0; i < dhdr->nscount; i++) {
- if ((cp = ntohrr (rrpp, msg, cp)) == NULLCHAR) {
- free (msg);
- return -1;
- }
- (*rrpp)->source = RR_AUTHORITY;
- rrpp = &(*rrpp)->next;
- }
- *rrpp = NULLRR;
-
- /* Additional section */
- rrpp = &dhdr->additional;
- for (i = 0; i < dhdr->arcount; i++) {
- if ((cp = ntohrr (rrpp, msg, cp)) == NULLCHAR) {
- free (msg);
- return -1;
- }
- (*rrpp)->source = RR_ADDITIONAL;
- rrpp = &(*rrpp)->next;
- }
- *rrpp = NULLRR;
- free (msg);
- return 0;
- }
-
-
- static char *
- getq (rrpp, msg, cp)
- struct rr **rrpp;
- char *msg;
- char *cp;
- {
- register struct rr *rrp;
- int len;
- char *name;
-
- *rrpp = rrp = (struct rr *) callocw (1, sizeof (struct rr));
-
- name = mallocw (512);
- len = dn_expand (msg, NULLCHAR, cp, name, 512);
- if (len == -1) {
- free (name);
- return NULLCHAR;
- }
- cp += len;
- rrp->name = strdup (name);
- rrp->type = get16 (cp);
- cp += 2;
- rrp->class = get16 (cp);
- cp += 2;
- rrp->ttl = 0;
- rrp->rdlength = 0;
- free (name);
- return cp;
- }
-
-
- /* Read a resource record from a domain message into a host structure */
- static char *
- ntohrr (rrpp, msg, cp)
- struct rr **rrpp; /* Where to allocate resource record structure */
- char *msg; /* Pointer to beginning of domain message */
- char *cp; /* Pointer to start of encoded RR record */
- {
- register struct rr *rrp;
- int len;
- char *name;
-
- *rrpp = rrp = (struct rr *) callocw (1, sizeof (struct rr));
-
- name = mallocw (512);
- if ((len = dn_expand (msg, NULLCHAR, cp, name, 512)) == -1) {
- free (name);
- return NULLCHAR;
- }
- cp += len;
- rrp->name = strdup (name);
- rrp->type = get16 (cp);
- cp += 2;
- rrp->class = get16 (cp);
- cp += 2;
- rrp->ttl = (int32) get32 (cp);
- cp += 4;
- rrp->rdlength = get16 (cp);
- cp += 2;
- switch (rrp->type) {
- case TYPE_A:
- /* Just read the address directly into the structure */
- rrp->rdata.addr = get32 (cp);
- cp += 4;
- break;
- case TYPE_CNAME:
- case TYPE_MB:
- case TYPE_MG:
- case TYPE_MR:
- case TYPE_NS:
- case TYPE_PTR:
- /* These types all consist of a single domain name;
- * convert it to ascii format
- */
- len = dn_expand (msg, NULLCHAR, cp, name, 512);
- if (len == -1) {
- free (name);
- return NULLCHAR;
- }
- rrp->rdata.name = strdup (name);
- rrp->rdlength = (int16) strlen (name);
- cp += len;
- break;
- case TYPE_HINFO:
- len = *cp++;
- rrp->rdata.hinfo.cpu = mallocw ((unsigned) len + 1);
- memcpy (rrp->rdata.hinfo.cpu, cp, (size_t) len);
- rrp->rdata.hinfo.cpu[len] = '\0';
- cp += len;
-
- len = *cp++;
- rrp->rdata.hinfo.os = mallocw ((unsigned) len + 1);
- memcpy (rrp->rdata.hinfo.os, cp, (size_t) len);
- rrp->rdata.hinfo.os[len] = '\0';
- cp += len;
- break;
- case TYPE_MX:
- rrp->rdata.mx.pref = get16 (cp);
- cp += 2;
- /* Get domain name of exchanger */
- len = dn_expand (msg, NULLCHAR, cp, name, 512);
- if (len == -1) {
- free (name);
- return NULLCHAR;
- }
- rrp->rdata.mx.exch = strdup (name);
- cp += len;
- break;
- case TYPE_SOA:
- /* Get domain name of name server */
- len = dn_expand (msg, NULLCHAR, cp, name, 512);
- if (len == -1) {
- free (name);
- return NULLCHAR;
- }
- rrp->rdata.soa.mname = strdup (name);
- cp += len;
-
- /* Get domain name of responsible person */
- len = dn_expand (msg, NULLCHAR, cp, name, 512);
- if (len == -1) {
- free (name);
- return NULLCHAR;
- }
- rrp->rdata.soa.rname = strdup (name);
- cp += len;
-
- rrp->rdata.soa.serial = (int32) get32 (cp);
- cp += 4;
- rrp->rdata.soa.refresh = (int32) get32 (cp);
- cp += 4;
- rrp->rdata.soa.retry = (int32) get32 (cp);
- cp += 4;
- rrp->rdata.soa.expire = (int32) get32 (cp);
- cp += 4;
- rrp->rdata.soa.minimum = (int32) get32 (cp);
- cp += 4;
- break;
- case TYPE_TXT:
- /* Just stash */
- rrp->rdata.data = mallocw ((unsigned) rrp->rdlength);
- memcpy (rrp->rdata.data, cp, (size_t) rrp->rdlength);
- cp += rrp->rdlength;
- break;
- default:
- /* Ignore */
- cp += rrp->rdlength;
- break;
- }
- free (name);
- return cp;
- }
-
-
- /* Convert a compressed domain name to the human-readable form */
- static int
- dn_expand (msg, eom, compressed, full, fullen)
- char *msg; /* Complete domain message */
- char *eom OPTIONAL;
- char *compressed; /* Pointer to compressed name */
- char *full; /* Pointer to result buffer */
- int fullen; /* Length of same */
- {
- unsigned int slen; /* Length of current segment */
- register char *cp;
- int clen = 0; /* Total length of compressed name */
- int indirect = 0; /* Set if indirection encountered */
- int nseg = 0; /* Total number of segments in name */
-
- cp = compressed;
- for (;;) {
- slen = uchar (*cp++); /* Length of this segment */
- if (!indirect)
- clen++;
- if ((slen & 0xc0) == 0xc0) {
- if (!indirect)
- clen++;
- indirect = 1;
- /* Follow indirection */
- cp = &msg[((slen & 0x3f) << 8) + uchar (*cp)];
- slen = uchar (*cp++);
- }
- if (slen == 0) /* zero length == all done */
- break;
- fullen -= (int) (slen + 1);
- if (fullen < 0)
- return -1;
- if (!indirect)
- clen += (int) slen;
- while (slen-- != 0)
- *full++ = *cp++;
- *full++ = '.';
- nseg++;
- }
- if (nseg == 0) {
- /* Root name; represent as single dot */
- *full++ = '.';
- fullen--;
- }
- *full++ = '\0';
- fullen--;
- return clen; /* Length of compressed message */
- }
-
-
-
- #ifdef DSERVER
-
- /* Most of this code is based on the DNS server in PA0GRI's 910828
- * Ported to the current NOS code by Johan. K. Reinalda, WG7J
- * for version and bug/feature info, see domain.c
- */
-
- static char *
- dn_compress (cp, name)
- char *cp, *name;
- {
- int len, dlen;
- char *cp1;
- char *nametmp;
-
- if (!name)
- return cp;
- dlen = (int) strlen (name);
- for (;;) {
- /* Look for next dot */
- cp1 = strchr (name, '.');
- if (cp1 != NULLCHAR)
- len = cp1 - name; /* More to come */
- else
- len = dlen; /* Last component */
- *cp++ = (char) len; /* Write length of component */
- if (len == 0)
- return cp;
- /* Copy component up to (but not including) dot */
- nametmp = name;
- strncpy (cp, nametmp, (size_t) len);
- cp += len;
- if (cp1 == NULLCHAR) {
- *cp++ = 0; /* Last one; write null and finish */
- return cp;
- }
- name += len + 1;
- dlen -= len + 1;
- }
- }
-
-
- /* Translate a resource record from host format to network format */
- static char *
- htonrr (rr, buffer)
- struct rr *rr;
- char *buffer;
- {
- struct rr *rrp;
- unsigned char *cp, *p;
- int i, len;
-
- cp = (unsigned char *) buffer;
- for (rrp = rr; rrp != NULLRR; rrp = rrp->next) {
- #ifdef notdef
- i = strlen (rrp->name);
- if (rrp->name[i - 1] != '.'
- && rrp->origin != NULLCHAR) {
- p = mallocw (i + strlen (rrp->origin) + 2);
- sprintf (p, "%s.%s", rrp->name, rrp->origin);
- cp = dn_compress (cp, p);
- free (p);
- } else
- #endif
- cp = (unsigned char *) dn_compress ((char *) cp, rrp->name);
- cp = put16 (cp, rrp->type);
- cp = put16 (cp, rrp->class);
- cp = put32 (cp, (uint32) rrp->ttl);
- #ifdef notdef
- /* The length doesn't seem to be right for all types ! */
- cp = put16 (cp, rrp->rdlength);
- #endif
- p = cp; /* This is where the length goes ! */
- cp += 2; /* Save the space for lenght field */
-
- switch (rrp->type) {
- case TYPE_A:
- cp = put32 (cp, rrp->rdata.addr);
- break;
- case TYPE_SOA:
- cp = (unsigned char *) dn_compress ((char *) cp, rrp->rdata.soa.mname);
- cp = (unsigned char *) dn_compress ((char *) cp, rrp->rdata.soa.rname);
- cp = put32 (cp, (uint32) rrp->rdata.soa.serial);
- cp = put32 (cp, (uint32) rrp->rdata.soa.refresh);
- cp = put32 (cp, (uint32) rrp->rdata.soa.retry);
- cp = put32 (cp, (uint32) rrp->rdata.soa.expire);
- cp = put32 (cp, (uint32) rrp->rdata.soa.minimum);
- break;
- case TYPE_HINFO:
- len = (int) strlen (rrp->rdata.hinfo.cpu);
- *cp++ = uchar(len);
- strncpy ((char *) cp, rrp->rdata.hinfo.cpu, (size_t) len);
- cp += len;
- len = (int) strlen (rrp->rdata.hinfo.os);
- *cp++ = uchar(len);
- strncpy ((char *) cp, rrp->rdata.hinfo.os, (size_t) len);
- cp += len;
- break;
- case TYPE_MX:
- cp = put16 (cp, rrp->rdata.mx.pref);
- cp = (unsigned char *) dn_compress ((char *) cp, rrp->rdata.mx.exch);
- break;
- case TYPE_CNAME:
- case TYPE_MB:
- case TYPE_MG:
- case TYPE_MR:
- case TYPE_NS:
- case TYPE_PTR:
- cp = (unsigned char *) dn_compress ((char *) cp, rrp->rdata.data);
- break;
- case TYPE_MINFO: /* Unsupported type */
- cp = (unsigned char *) dn_compress ((char *) cp, rrp->rdata.minfo.rmailbx);
- cp = (unsigned char *) dn_compress ((char *) cp, rrp->rdata.minfo.emailbx);
- /* fall through */
- case TYPE_MD: /* Unsupported type */
- case TYPE_MF: /* Unsupported type */
- case TYPE_NULL:/* Unsupported type */
- case TYPE_WKS: /* Unsupported type */
- cp = (unsigned char *) dn_compress ((char *) cp, rrp->rdata.data);
- break;
- case TYPE_TXT:
- default:
- cp = put16 (cp, rrp->rdlength);
- for (i = 0; i < rrp->rdlength; i++)
- *cp++ = uchar(rrp->rdata.data[i]);
- break;
- }
- /* Calculate the lenght of the RR */
- len = cp - p - 2;
- (void) put16 (p, (int16) len); /* and set it */
- }
- return (char *) cp;
- }
-
-
- int
- htondomain (dhdr, buffer, buflen)
- struct dhdr *dhdr;
- char *buffer; /* Area for query */
- int16 buflen OPTIONAL; /* Length of same */
- {
- unsigned char *cp;
- struct rr *rrp;
- int16 parameter;
- int i, count;
- int done = 0;
-
- cp = (unsigned char *) buffer;
- cp = put16 (cp, dhdr->id);
- if (dhdr->qr)
- parameter = 0x8000;
- else
- parameter = 0;
- parameter |= (dhdr->opcode & 0x0f) << 11;
- if (dhdr->aa)
- parameter |= DOM_AUTHORITY;
- if (dhdr->tc)
- parameter |= DOM_TRUNC;
- if (dhdr->rd)
- parameter |= DOM_DORECURSE;
- if (dhdr->ra)
- parameter |= DOM_CANRECURSE;
- parameter |= (dhdr->rcode & 0x0f);
- cp = put16 (cp, parameter);
- cp = put16 (cp, dhdr->qdcount);
- cp = put16 (cp, dhdr->ancount);
- cp = put16 (cp, dhdr->nscount);
- cp = put16 (cp, dhdr->arcount);
- if ((count = dhdr->qdcount) > 0) {
- rrp = dhdr->questions;
- for (i = 0; i < count; i++) {
- cp = (unsigned char *) dn_compress ((char *) cp, rrp->name);
- cp = put16 (cp, rrp->type);
- cp = put16 (cp, rrp->class);
- rrp = rrp->next;
- }
- }
-
- if (((char *) cp - buffer) > buflen)
- done = 1;
-
- if (!done && (count = dhdr->ancount) > 0) {
- rrp = dhdr->answers;
- for (i = 0; i < count; i++) {
- cp = (unsigned char *) htonrr (rrp, (char *) cp);
- if (((char *) cp - buffer) > buflen) {
- done = 1;
- break;
- }
- rrp = rrp->next;
- }
- }
- if (!done && (count = dhdr->nscount) > 0) {
- rrp = dhdr->authority;
- for (i = 0; i < count; i++) {
- cp = (unsigned char *) htonrr (rrp, (char *) cp);
- if (((char *) cp - buffer) > buflen) {
- done = 1;
- break;
- }
- rrp = rrp->next;
- }
- }
- if (!done && (count = dhdr->arcount) > 0) {
- rrp = dhdr->additional;
- for (i = 0; i < count; i++) {
- cp = (unsigned char *) htonrr (rrp, (char *) cp);
- if (((char *) cp - buffer) > buflen) {
- done = 1;
- break;
- }
- rrp = rrp->next;
- }
- }
- return ((char *) cp - buffer);
- }
-
- #endif /* DSERVER */
-